<template>
	<view class="box_doc">
		<view class="h3">Flutter学习笔记</view>
		<view class="tip">介绍</view>
		<view class="text">
      Flutter是谷歌的移动UI框架，可以快速在iOS和Android上构建高质量的原生用户界面。 Flutter可以与现有的代码一起工作。在全世界，Flutter正在被越来越多的开发者和组织使用，并且Flutter是完全免费、开源的。
		</view>
    <view class="bold">app 开发运行机制</view>
    <view class="li">原生APP ： java -> 图形渲染引擎 -> GPU -> UI界面</view>
    <view class="li">React-Native：js -> java -> 图形渲染引擎 -> GPU -> UI界面</view>
    <view class="li">Flutter：Flutter -> Dart -> 图形渲染引擎 -> GPU -> UI界面</view>

		<view class="tip">一、在macOS上搭建Flutter开发环境</view>
    <zero-markdown-view :markdown="content[0]"></zero-markdown-view>
    <view class="li">通过 flutter create flutter_demo 创建一个flutter项目</view>
    <view class="li">cd flutter_demo</view>
    <view class="li">flutter run 运行项目</view>
		<view class="tip">二、常用快捷键</view>
    <view class="li">r 键：热加载(快速部署)。</view>
    <view class="li">p 键：显示网格，用于开发时调试UI。</view>
    <view class="li">o 键：切换Android和iOS的预览模式。</view>
    <view class="li">q 键：退出调试预览模式。 以上几个按键需要已经执行过flutter run之后才可以在终端中使用。</view>

		<view class="tip">三、基本Widget组件</view>
		<view class="text">Flutter中一切皆组件(Widget)。所有的自定义组件、系统组件、自定义页面等其实都是Widget的子类。每个widget的构造函数都有一个key参数，这个参数的作用是什么呢？Key用于在widget的位置改变时保留其状态。比如，保留用户的滑动位置，或者在保留widget状态的情况下修改一个widget集合，如Row、Column等，这一篇博客详细d 讲解了Widget中的key。</view>
		<view class="bold">3-1 有状态无状态组件。</view>
		<view class="text">
      Flutter中如果要自定组件，一般都继承自有状态组件或无状态组件(小到组件大到页面)，如果一个页面加载出来之后就不会再改变了那么就继承自StatelessWidget，如果加载之后还需要根据数据的变化而变化，那么就需要继承自StatefulWidget。
    </view>
		<view class="text">1.StatelessWidget 无状态组件。
      <br /> ​ StatelessWidget组件是一个抽象类，继承该组件必须要实现Widget build(BuildContext context)方法。
    </view>
    <zero-markdown-view :markdown="content[1]"></zero-markdown-view>
    
		<view class="text">2.StatefulWidget 有状态组件。
      <br /> ​StatefulWidget是一个抽象组件，继承该组件必须要实现State StatefulWidget createState()方法。该方法需要返回一个State类的实例。而State是一个抽象类，要继承State需要实现Widget build(BuildContext context)抽象方法，并制定泛型为拥有该State的Widget。
      <br />​ 如果要实现改变状态，需要使用State类中的setState方法。下面的栗子是点击按钮后按钮上面的数字动态加1，具体代码如下：
    </view>
    <zero-markdown-view :markdown="content[2]"></zero-markdown-view>
    <view class="bold">3-2 装饰组件</view>
    <view class="text">1.MaterialApp。<br /> ​ 
      MaterialApp是一个方便的Widget，他封装了应用程序实现 Material Design 所需要的一些Widget。一般作为一个页面的最顶层的Widget使用。
    </view>
    <zero-markdown-view :markdown="content[3]"></zero-markdown-view>
    <view class="text">2.Scaffold<br /> ​ 
      ​ Scaffold 是 Material Design 布局结构的基本实现。此类提供了用于显示 drawer、snackbar 和底部的 sheet 的参数。
    </view>
    <zero-markdown-view :markdown="content[4]"></zero-markdown-view>
    <view class="text">3.InkWell & GestureDetector 手势组件<br /> ​ 
      ​ 在Flutter中并不是所有的Widget都支持点击事件，但是如果我们想给某些我们自己的Widget设置点击事件时应该怎么办呢(例如我们列表中的item)？这时我们只需要使用InkWell将我们要设置点击事件的Widget包裹起来就可以了。
    </view>
    <zero-markdown-view :markdown="content[5]"></zero-markdown-view>
    
    <view class="text">GestureDetector和InkWell用法基本一致，只是GestureDetector比InkWell多了更多回调设置，可以监听更多的事件。</view>
    <view class="bold">3-3 Container 容器组件</view>
    <zero-markdown-view :markdown="content[6]"></zero-markdown-view>
    <view class="bold">3-4. Text 文本组件</view>
    <zero-markdown-view :markdown="content[7]"></zero-markdown-view>
    <view class="bold">3-5. ListView 列表组件</view>
    <zero-markdown-view :markdown="content[8]"></zero-markdown-view>
    <view class="li">静态列表</view>
    <zero-markdown-view :markdown="content[9]"></zero-markdown-view>
    <view class="li">动态列表</view>
    <zero-markdown-view :markdown="content[10]"></zero-markdown-view>
    <view class="li">上拉加载更多</view>
    <view class="text">上拉加载更多有两种实现方式：<br /> 1.可以在itemBuilder回调中处理，判断当前index的数值，当构建最后一个条目时触发加载更多。</view>
    <zero-markdown-view :markdown="content[11]"></zero-markdown-view>
    <view class="text">2.可以利用ListView的controller属性监听列表的滚动。具体有以下几个步骤：<br />(1)、声明一个ScrollController变量</view>
    <zero-markdown-view :markdown="content[12]"></zero-markdown-view>
    <view class="text">(2)、在initState生命周期中设置监听并判断滚动距离。</view>
    <zero-markdown-view :markdown="content[13]"></zero-markdown-view>
    <view class="text">(3)、为ListView增加controller属性。</view>
    <zero-markdown-view :markdown="content[14]"></zero-markdown-view>
    <view class="text">到此上拉加载更多就已经实现了，但是这里还有问题。那就是如果我们已经加载完成了最后一页，我们不断的上拉会不断的请求接口，尽管接口会返回空的数据。所以我们还需要对此做进一步处理。</view>
    <view class="bold">3-6. RefreshIndicator下拉刷新组件</view>
    <zero-markdown-view :markdown="content[15]"></zero-markdown-view>
    <zero-markdown-view :markdown="content[16]"></zero-markdown-view>
    <view class="bold">3-7. GridView</view>
    <zero-markdown-view :markdown="content[17]"></zero-markdown-view>
    <view class="text">静态列表</view>
    <zero-markdown-view :markdown="content[18]"></zero-markdown-view>
    <view class="text">动态列表</view>
    <zero-markdown-view :markdown="content[19]"></zero-markdown-view>
    <view class="bold">3-8. Padding 内边距组件</view>
    <zero-markdown-view :markdown="content[20]"></zero-markdown-view>
    <view class="bold">3-9. Row 水平布局组件</view>
    <zero-markdown-view :markdown="content[21]"></zero-markdown-view>
    <view class="bold">3-10. Column 垂直布局组件</view>
    <zero-markdown-view :markdown="content[22]"></zero-markdown-view>
    <view class="bold">3-11. Expanded 组件，类似Web中的Flex布局</view>
    <zero-markdown-view :markdown="content[23]"></zero-markdown-view>
    <view class="bold">3-12. SizedBox 占位组件</view>
    <zero-markdown-view :markdown="content[24]"></zero-markdown-view>
    <view class="bold">3-13. Stack 层叠组件</view>
    <zero-markdown-view :markdown="content[25]"></zero-markdown-view>
    <view class="bold">3-14. Align</view>
    <zero-markdown-view :markdown="content[26]"></zero-markdown-view>
    <view class="bold">3-15. Positioned</view>
    <zero-markdown-view :markdown="content[27]"></zero-markdown-view>
    <view class="bold">3-16. AspectRatio</view>
    <zero-markdown-view :markdown="content[28]"></zero-markdown-view>
    <view class="bold">3-17. Card</view>
    <zero-markdown-view :markdown="content[29]"></zero-markdown-view>
    <view class="bold">3-18. CircleAvatar 原型头像组件</view>
    <zero-markdown-view :markdown="content[30]"></zero-markdown-view>
    <view class="bold">3-19. Wrap组件(流式布局组件)</view>
    <zero-markdown-view :markdown="content[31]"></zero-markdown-view>
    <view class="bold">3-20. 按钮组件</view>
    <view class="text">Flutter中给我们预先定义好了一些按钮控件给我们用，常用的按钮如下</view>
    <view class="li">RaisedButton ：凸起的按钮，其实就是Android中的Material Design风格的Button ，继承自MaterialButton如果要让RaisedButton支持图标，那么可以使用RaisedButton.icon()。</view>
    <view class="li">FlatButton ：扁平化的按钮，继承自MaterialButton</view>
    <view class="li">OutlineButton ：带边框的按钮，继承自MaterialButton</view>
    <view class="li">IconButton ：图标按钮,继承自StatelessWidget</view>
    <view class="li">FloatingActionButton : 浮动按钮,继承自StatelessWidget</view>
    <view class="text">按钮通常情况下是不能直接设置宽高的，如果要设置宽高可是在外层包一个Container组件。也可以在外层包一个Expanded组件使其可以自适应宽度。<br />常用属性如下</view>
    <zero-markdown-view :markdown="content[32]"></zero-markdown-view>
    <!-- <zero-markdown-view :markdown="```js\n\n```"></zero-markdown-view> -->
    <!-- <zero-markdown-view :markdown="\n\n"></zero-markdown-view> -->
	</view>
</template>
<script>
export default {
	data() {
		return {
			content:[
        "\n具体见：[Flutter中文网](https://flutterchina.club/setup-macos/)\n",
        "```js\nclass MyApp extends StatelessWidget {\n  // This widget is the root of your application.\n  @override\n  Widget build(BuildContext context) {\n    return Text('Hello Flutter!');\n  }\n}\n```",
        "```js\nclass TestPage extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return Container(\n      padding: EdgeInsets.all(20),\n      child: Custom(),\n    );\n  }\n}\n\nclass Custom extends StatefulWidget{\n  @override\n  State<StatefulWidget> createState() {\n    return _CustomState();\n  }\n}\n\nclass _CustomState extends State<Custom>{\n  var myNumber = 0;\n  @override\n  Widget build(BuildContext context) {\n    return Column(\n      children: [\n        Text('$myNumber'),\n        SizedBox(height: 20),\n        RaisedButton(\n          onPressed: () {\n            setState(() {\n              myNumber++;\n            });\n          },\n          child: Text('增加'),\n        )\n      ],\n    );\n  }\n}\n```",
        "\n参数|类型|可选|默认值|说明\n:--:|:--:|:--:|:--:|:--:\nhome|Widget|是|--|页面的具体内容组件\ntitle|String|是|''|页面标题。\ncolor|Color|是|--|页面颜色。\ntheme|ThemeData|是|--|页面主题。\nroutes|Map< String, WidgetBuilder>|是|const < String, WidgetBuilder>{}|路由。\n",
        "\n参数|类型|可选|默认值|说明\n:--:|:--:|:--:|:--:|:--:\nappBar|Widget|是|--|导航栏\nbody|Widget|是|--|\ndrawer|Widget|是|--|\nbottomNavigationBar|Widget|是|--|\n",
        "\n参数|类型|可选|默认值|说明\n:--:|:--:|:--:|:--:|:--:\nchild|Widget|是|--|子组件|\nonTap|GestureTapCallback|是|--|单击事件回调\nonDoubleTap|GestureTapCallback|是|--|双击事件回调\nonLongPress|GestureLongPressCallback|是|--|长按事件回调\n",
        "\n参数|类型|可选|默认值|说明\n:--:|:--:|:--:|:--:|:--:\nconstraints|BoxConstraints|是|--|用不约束宽高(最大宽高、最小宽高等)\nalignment|AlignmentGeometry|是|--|对齐方式\ndecoration|Decoration|是|--|设置边框装饰\npadding|EdgeInsetsGeometry|是|--|内边距\nmargin|EdgeInsetsGeometry|是|--|外边距\ntransform|Matrix4|是|--|旋转、平移\n",
        "\n参数|类型|可选|默认值|说明\n:--:|:--:|:--:|:--:|:--:\ndata|String|否|--|用于设置现在界面上的文字\ntextAlign|TextAlign|是|--|center:居中 / left:居左 / right：居右 / justfy：两端对齐\ntextDirection|TextDirection|是|--|文本方向，ltr：从左至右 rtl：从右至左\noverflow|TextOverflow|是|--|文字超出屏幕后的处理方式，clip：裁剪 fade：渐隐 ellipsis：省略号\nstyle|TextStyle|是|--|用于设置文字的样式\nmaxLines|int|是|--|用于设置文字的最大显示行数\ntextScaleFactor|double|是|--|字体显示倍率\n",
        "\n参数|类型|可选|默认值|说明\n:--:|:--:|:--:|:--:|:--:\nitemCount|Int|必填|--|设置列表一共有多少个条目\nitemBuilder|Widget Function(BuildContext context, int index)|必填|--|用于构建item(cell)视图的回调方法。\nscrollDirection|Axis|是|Axis.vertical|滚动方向：horizontal-横向 vertical纵向。\nreverse|bool|是|false|是否反向排列。\nkeyboard DismissBehavior|ScrollViewKeyboard DismissBehavior|是|ScrollViewKeyboard DismissBehavior.manual|滚动时键盘的处理方式。\n",
        "```js\n@override\nWidget build(BuildContext context) {\n  return ListView(\n    children: [\n      Text('我是一个条目'),\n      Text('我是一个条目'),\n      Text('我是一个条目'),\n      Text('我是一个条目'),\n      Text('我是一个条目'),\n      Text('我是一个条目'),\n    ],\n  );\n}\n```",
        "```js\n@override\nWidget build(BuildContext context) {\n  return ListView.builder(\n      itemCount: 5,\n      itemBuilder: (context, index){\n        return ListTile(\n          leading: data[index].avatarUrl,\n          title: data[index].name,\n          subtitle: data[index].desc,\n        );\n      }\n  );\n}\n```",
        "```js\n@override\nWidget build(BuildContext context) {\n  return ListView.builder(\n      itemCount: this._data.length,\n      itemBuilder: (context, index){\n        if (index == this._data.length) {\n          onLoadMore();  //触发loadMore()\n        }\n        return ListTile(\n          leading: this._data[index].avatarUrl,\n          title: this._data[index].name,\n          subtitle: this._data[index].desc,\n        );\n      }\n  );\n}\n```",
        "```js\nScrollController _scrollController = ScrollController();\n```",
        "```js\n@override\nvoid initState() {\n  super.initState();\n  this._scrollController.addListener(() {\n    if(this._scrollController.position.pixels > this._scrollController.position.maxScrollExtent - 50) {\n      onLoadMore();   //当滚动接近底部时触发加载更多。\n    }\n  });\n}\n```",
        "```js\nListView.builder(\n  controller: _scrollController,\n  itemCount: this._data.length,\n  itemBuilder: (context, index){\n    return ListTile(\n      leading: this._data[index].avatarUrl,\n      title: this._data[index].name,\n      subtitle: this._data[index].desc,\n    );\n  }\n);\n```",
        "\n参数|类型|可选|默认值|说明\n:--:|:--:|:--:|:--:|:--:\nchild|Widget|必填|--|用来绘制内容视图，通常应该是ListView。\nonRefresh|Future< void> Function|必填|--|下拉刷新的监听\ncolor|Color|是|主题色|设置颜色\ndisplacement|double|是|40.0|设置下拉多少距离触发下拉刷新\n",
        "```js\nRefreshIndicator(\n  child: ListView.builder(\n    itemCount: _dataList.length,\n    itemBuilder: _createItemCell\n  ),\n  onRefresh: () => Future.delayed(Duration(), () => onRefresh()),\n);\n```",
        "\n参数|类型|可选|默认值|说明\n:--:|:--:|:--:|:--:|:--:\ncrossAxisSpacing|double|是|--|水平间距\nmainAxisSpacing|double|是|--|垂直间距\nscrollDirection|Axis|是|Axis.vertical|滚动方向：horizontal-横向 vertical纵向。\nreverse|bool|是|false|是否反向排列。\nchildAspecet|double|是|--|item的宽高比例。\ncrossAxisCount|int|是|--|设置列数\ngridDelegate|SliverGridDelegate|必填|--|builder专用。用于设置间距列数等。\nitemBuilder|Widget Function(BuildContext context, int index)|必填|--|builder专用。用于构建item(cell)视图的回调方法。\n",
        "```js\n@override\nWidget build(BuildContext context) {\n  return GridView.count(\n      crossAxisCount: 2,\n      children: [\n        Text('我是一个条目'),\n        Text('我是一个条目'),\n        Text('我是一个条目'),\n        Text('我是一个条目'),\n        Text('我是一个条目'),\n        Text('我是一个条目'),\n        Text('我是一个条目'),\n        Text('我是一个条目'),\n        Text('我是一个条目'),\n        Text('我是一个条目')\n      ],\n  );\n}\n```",
        "```js\n@override\nWidget build(BuildContext context) {\n  return GridView.builder(\n      itemCount: 600,\n      gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(\n        crossAxisCount: 3\n      ),\n      itemBuilder: (context, position){\n        return Text('我是第$position个条目');\n      }\n  );\n}\n```",
        "\n参数|类型|可选|默认值|说明\n:--:|:--:|:--:|:--:|:--:\npadding|EdgeInsetsGeometry|必填|--|用于设置内边距，其实是设置child的外边距。\nchild|Widget|是|--|子元素。\n",
        "\n参数|类型|可选|默认值|说明\n:--:|:--:|:--:|:--:|:--:\nmainAxisAlignment|MainAxisAlignment|是|MainAxisAlignment.start|主轴的排序方式\ncrossAxisAlignment|CrossAxisAlignment|是|CrossAxisAlignment.center|次轴的排序方式\nchildren|List< Widget>|是|const < Widget>[]|子组件\n",
        "\n参数|类型|可选|默认值|说明\n:--:|:--:|:--:|:--:|:--:\nmainAxisAlignment|MainAxisAlignment|是|MainAxisAlignment.start|主轴的排序方式\ncrossAxisAlignment|CrossAxisAlignment|是|CrossAxisAlignment.center|次轴的排序方式\nchildren|List< Widget>|是|const < Widget>[]|子组件\n",
        "\n参数|类型|可选|默认值|说明\n:--:|:--:|:--:|:--:|:--:\nflex|int|是|1|子组件的权重，用于分配剩余空间\nchild|Widget|是|--|子组件\n",
        "\n参数|类型|可选|默认值|说明\n:--:|:--:|:--:|:--:|:--:\nwidth|double|是|0|宽度\nheight|double|是|0|高度\nchild|Widget|是|--|子组件\n",
        "\n参数|类型|可选|默认值|说明\n:--:|:--:|:--:|:--:|:--:\nalignment|AlignmentGeometry|是|Alignment.center|子组件的对齐方式\nchildren|List<Widget>|是|const <Widget>[]|子组件\n",
        "\n参数|类型|可选|默认值|说明\n:--:|:--:|:--:|:--:|:--:\nalignment|AlignmentGeometry|是|Alignment.center|子组件的对齐方式\nchild|Widget|是|--|子组件\n",
        "\n参数|类型|可选|默认值|说明\n:--:|:--:|:--:|:--:|:--:\nleft|double|是|0|左偏移量\ntop|double|是|0|上偏移量\nright|double|是|0|右偏移量\nbottom|double|是|0|下偏移量\nchild|Widget|是|--|子组件\n",
        "\n参数|类型|可选|默认值|说明\n:--:|:--:|:--:|:--:|:--:\naspectRatio|double|是|--|子组件的宽高比\nchild|Widget|是|--|子组件\n",
        "\n参数|类型|可选|默认值|说明\n:--:|:--:|:--:|:--:|:--:\nmargin|EdgeInsetsGeometry|是|--|外边距\nshape|ShapeBorder|是|--|边框及阴影效果，还可以使用RoundedRectangleBorder对其设置圆角\nclipBehavior|Clip|是|Clip.none|对子组件的裁剪方式\nelevation|doublle|是|1.0|阴影高度\nchild|Widget|是|--|子组件\n",
        "\n参数|类型|可选|默认值|说明\n:--:|:--:|:--:|:--:|:--:\nradius|double|是|--|头像的半径\nbackgroundColor|Color|是|--|头像的背景颜色\nbackgroundImage|ImageProvider|是|--|头像的背景图片\nchild|Widget|是|--|子组件\n",
        "\n参数|类型|可选|默认值|说明\n:--:|:--:|:--:|:--:|:--:\nspacing|double|是|0.0|主轴的子组件之间的间隔\nrunSpacing|double|是|0.0|次轴的子组件之间的间隔\ndirection|Axis|是|Axis.horizontal|子组件的排列方向，horizontal横向，vertical纵向。\nalignment|WrapAlignment|是|WrapAlignment.start|主轴子组件的对齐方式。\nrunAlignment|WrapAlignment|是|WrapAlignment.start|次轴子组件的对齐方式。\ntextDirection|TextDirection|是|--|文本的排列方向\n",
        "\n参数|类型|可选|默认值|说明\n:--:|:--:|:--:|:--:|:--:\nonPressed|VoidCallback|必传|--|按下按钮时触发的回调方法，传null表示按钮禁用，会显示禁用相关样式。\nchild|Widget|是|--|子组件，不传就无法显示内容。\ntextColor|Color|是|--|文本颜色\ncolor|Color|是|--|按钮的颜色\ndisabledColor|Color|是|--|按钮禁用时的颜色\ndisabledTextColor|Color|是|--|按钮禁用时的文本颜色\nsplashColor|Color|是|--|点击按钮时水波纹的颜色\nhighlightColor|Color|是|--|点击（长按）按钮后按钮的颜色\nelevation|double|是|--|阴影的范围，值越大阴影范围越大\npadding|EdgeInsetsGeometry|是|--|内边距\nshape|ShapeBorder|是|--|设置按钮的形状\nminWidth|double|是|--|最小宽度\nheight|double|是|--|高度\nmaterialTapTargetSize|Material TapTargetSize|是|Material TapTargetSize. padded|由于按钮按下后通常会有阴影效果，所以按钮默认都会有边距，如果不希望有边距可以通过该属性设置，MaterialTapTargetSize.padded：有边距。MaterialTapTargetSize.shrinkWrap：无边距。\n",

      ]
		}
	},
	methods: {
		
	}
}
</script>
<style lang="less" scoped>
	.box_doc {
		width: 100vw;
		height: 100vh;
		padding: 0 10rpx;
		box-sizing: border-box;
	}
</style>